/*
 * scheduler.c
 *
 *  Created on: 2023��12��2��
 *      Author: taobo
 */

/// realize the interfaces
#include "scheduler.h"

/// require the interfaces
#include "stdint.h"		/// types
#include "systick.h"	/// get tick
#include "cpuload.h"	/// cpuload

/// define types
typedef struct
{
	uint32_t	tick1ms25;
	uint8_t		count1ms25;
	uint8_t		count5ms;
	uint8_t		flag5ms;
	uint8_t		count25ms;
}
Scheduler_Data_T;

/// define variables
Scheduler_Data_T Scheduler_Data;

/// private functions

static void scheduler_init(void)
{
	Scheduler_Data.tick1ms25 = 0;
	Scheduler_Data.count1ms25 = 0;

	/// user init
	scheduler_hook_init();
}

static void scheduler_run1ms25(void)
{
	/// increase 1.25ms counter
	Scheduler_Data.count1ms25++;

	/// run 1.25ms task
	scheduler_hook_task1ms25();

	/// run 2.5ms task
	if(Scheduler_Data.count1ms25 & 0x01)
	{
		scheduler_hook_task2ms5();
	}
	/// run 5ms task
	else if(Scheduler_Data.count1ms25 & 0x02)
	{
		scheduler_hook_task5ms();
	}
	/// run 10ms task
	else if(Scheduler_Data.count1ms25 & 0x04)
	{
		scheduler_hook_task10ms();
		/// execute 5msB group
		Scheduler_Data.flag5ms=1;
	}
	/// run 20ms task A
	else if(Scheduler_Data.count1ms25 & 0x08)
	{
		scheduler_hook_task20msA();
		/// execute 5msB group
		Scheduler_Data.flag5ms=1;
	}
	/// run 20ms task B
	else
	{
		scheduler_hook_task20msB();
		/// execute 5msB group
		Scheduler_Data.flag5ms=1;
	}
}

static void scheduler_run25ms(void)
{
	/// increase 25ms counter
	Scheduler_Data.count25ms++;

	/// run 25ms task E
	scheduler_hook_task25msE();

	/// run 50ms task
	if(Scheduler_Data.count25ms & 0x01)
	{
		scheduler_hook_task50ms();
	}
	/// run 100ms task
	else if(Scheduler_Data.count25ms & 0x02)
	{
		scheduler_hook_task100ms();
	}
	/// run 200ms task
	else if(Scheduler_Data.count25ms & 0x04)
	{
		scheduler_hook_task200ms();
	}
	/// run 400ms A task
	else if(Scheduler_Data.count25ms & 0x08)
	{
		scheduler_hook_task400msA();
	}
	/// run 400ms B task
	else
	{
		scheduler_hook_task400msB();
	}
}

static void scheduler_run5ms(void)
{
	/// increase 5ms counter
	Scheduler_Data.count5ms++;
	if(Scheduler_Data.count5ms>=5) Scheduler_Data.count5ms = 0;

	/// 5 groups
	switch(Scheduler_Data.count5ms)
	{
	case	0:	scheduler_hook_task25msA(); break;
	case	1:	scheduler_hook_task25msB(); break;
	case	2:	scheduler_hook_task25msC(); break;
	case	3:	scheduler_hook_task25msD(); break;
	default:	scheduler_run25ms(); break;
	}
}

static void scheduler_run(void)
{
	/// dead loop
	for(;;)
	{
		uint32_t tick;

		/// check tick
		tick = SysTick_GetTick();
		if( Scheduler_Data.tick1ms25 != tick )
		{
			/// tick changed, i.e. 1.25ms elapsed

			/// cpuload
			Cpuload_BeforeEnterTask();

			/// sync tick
			Scheduler_Data.tick1ms25 = tick;

			/// run 1.25ms group
			scheduler_run1ms25();

			/// run 5msB groups
			if(Scheduler_Data.flag5ms)
			{
				/// clear the flag
				Scheduler_Data.flag5ms = 0;
				/// run 5msB groups
				scheduler_run5ms();
			}

			/// cpuload
			Cpuload_AfterExitTask();
		}
		else
		{
			/// idle
		}
	}
}

/// global functions

void scheduler_main(void)
{
	scheduler_init();
	scheduler_run();
}

